package algorithm.leetcode.medium;

/*
 给出一个完全二叉树，求出该树的节点个数。
 完全二叉树的定义如下：在完全二叉树中，除了最底层节点可能没填满外，其余每层节点数都达到最大值，
 并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层，则该层包含 1~ 2h 个节点
 */

/**
 * @author jack.wu
 * @version 1.0
 * @date 2020/12/18
 */
public class Question222 {

    public static void main(String[] args) {
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        Question222 question = new Question222();
        int nodes = question.countNodes(root);
        System.out.println(nodes);
    }

    /**
     * dfs
     */
    public int countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        return countNodes(root.left) + countNodes(root.right) + 1;
    }

    /**
     * 公式 (2^(height-2))-1
     */
    public int countNodes1(TreeNode root) {
        // 因为题目给的是完全二叉树 根据完全二叉树性质  树的高度取决于左子树高度
        int height = treeHeight(root);
        if (height == 0 || height == 1) {
            // 说明树是空树或者只有一个根节点
            return height;
        }
        if (treeHeight(root.right) == height - 1) {
            // 右子树的高度是 树高度 - 1 说明左子树是满二叉树
            // 左子树和根节点个数 -> 1 << (height - 1)
            // 然后递归右子树
            return 1 << (height - 1) + countNodes1(root.right);
        }else {
            // 说明右子树是满二叉树
            // 右子树和根节点个数 -> 1 << (height - 2)
            // 然后递归左子树
            return (1 << (height - 2)) + countNodes1(root.left);
        }

    }

    private int treeHeight(TreeNode root) {
        return root == null ? 0 : 1 + treeHeight(root.left);
    }


    private static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode(int x) {
            val = x;
        }
    }
}
